using System;
using SMLib.Base;
using System.Collections.Generic;
using MBT.Utils;

namespace MBT.Conformance.OfflineTesting
{
	/// <summary>
	/// Offline Test Case Generation - path coverage strategy
	/// <remarks>
	/// Our definition of path coverage: all path starting from initial state
	/// that don't have any repeated state
	/// </remarks>
	/// </summary>
	public class OTCG_PathCoverage<STATETYPE, TRANSITIONTYPE>
	{
		IDiGraph<STATETYPE, TRANSITIONTYPE> model;
		
		/// <summary>
		/// Initializes a new instance of the <see cref="MBT.OTCG_PathCoverage"/> class.
		/// </summary>
		/// <param name='model'>
		/// Model.
		/// </param>
		public OTCG_PathCoverage (IDiGraph<STATETYPE, TRANSITIONTYPE> model)
		{
			this.model=model;			
		}
		
		/// <summary>
		/// Enumerates the test cases.
		/// </summary>
		/// <returns>
		/// The test cases.
		/// </returns>
		public IEnumerable<List<TRANSITIONTYPE>> EnumerateTestCases()
        {
			List<TRANSITIONTYPE> testCase=new List<TRANSITIONTYPE>();
			List<int> selectedEdges = new List<int> ();
			List<int> selectedStates = new List<int>();
			
			selectedStates.Add(0);
			selectedEdges.Add(0);
			int len=1;
			
			STATETYPE currentState,nextState;
			TRANSITIONTYPE currentEdge;
			do
			{
				len=selectedStates.Count;
				
				#region =-[ Select one test ]=-
				//* the test case can be at most size of N
				for(int i=0;i<model.Size;i++)
				{
					currentState=model[selectedStates[len-1]];
					//* dead state?
					if(model.TransitionsOf(currentState).Count==0)
					{
						break;
					}
					currentEdge =model.TransitionsOf(currentState)[selectedEdges[len-1]];					
					nextState = model.DestinationOf(currentEdge);
					
					int nextStateIndex=model.IndexOf(nextState);
					
					if(selectedStates.Contains(nextStateIndex))
					{
						//* a repeated state swas seen!
						break;
					}
					else
					{
						//* add one step!
						selectedStates.Add(nextStateIndex);
						selectedEdges.Add(0);
						len++;
					}
				}
				
				#endregion
				
				testCase.Clear();
				//* create test case from model
				for(int i=0;i<len;i++)
				{
					currentState=model[selectedStates[i]];
					currentEdge =model.TransitionsOf(currentState)[selectedEdges[i]];	
					testCase.Add(currentEdge);
				}
				yield return testCase;
				//ListUtil.WriteList(testCase,",");
				//Console.WriteLine();
				
				for(int j=len-1;j>=0;j--)
				{
					currentState=model[selectedStates[j]];
					selectedEdges[j]++;
					if(model.TransitionsOf(currentState).Count>selectedEdges[j])
					{
							//* enough going back!
							break;
					}
					else
					{
						selectedEdges.RemoveAt(selectedEdges.Count-1);
						selectedStates.RemoveAt(selectedStates.Count-1);
						len--;						
					}
				}
				if (len<=0)
					break;
			}while(true);			
		}
	}
}

